/* gearserial_interface.c -- Gera a interface
 *
 * Copyright (C) 2007, Diogo F. S. Ramos <diogofsr at gmail.com>
 * GEAR - Grupo de Estudos Avançados em Robótica
 * <http://www.sel.eesc.usp.br/gear>
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <stdlib.h>
#include <glade/glade.h>

#include "gearserial_interface.h"
#include "gearserial.h"
#include "xmalloc.h"
#include "xerror.h"

static gint
gearserial_interface_event_handler(GtkWidget *widget,
				   GdkEvent *event,
				   gpointer user_data );
static void
gearserial_interface_destroy( GtkWidget *widget,
			      gpointer user_data );
static void
gearserial_interface_callback_handler( GtkWidget *widget,
				       gpointer user_data );
static void
gearserial_interface_dialog_handler( GtkWidget *widget,
				     gint arg1,
				     gpointer user_data );

GearSerialInterface *
gearserial_interface_new( void )
{
    GearSerialInterface *self = XMALLOC( GearSerialInterface, 1 );

    return self;
}

int
gearserial_interface_init( GearSerialInterface * self,
			   const char * end_glade,
			   GearSerial *gserial )
{
    GladeXML *xml = NULL;    

    xml = glade_xml_new(end_glade, NULL, NULL );

    /* Arrumando os ponteiros da estrutura */
    self->gserial                    = gserial;
    self->main_window                = glade_xml_get_widget( xml,
							     "main_window" );
    self->action_area                = glade_xml_get_widget( xml,
							     "action_area" );
    self->dialog_abre_serial         = glade_xml_get_widget( xml,
							     "dialog_abre_serial" );
    self->imagemenuitem_abrir_serial = glade_xml_get_widget( xml,
							     "imagemenuitem_abrir_serial" );
    self->entry_abre_serial          = glade_xml_get_widget( xml,
							     "entry_abre_serial" );
    self->button_start               = glade_xml_get_widget( xml,
							     "button_start" );
    self->button_stop                = glade_xml_get_widget( xml,
							     "button_stop" );
    self->radio_buttons[RADIO_BUTTON_300] = glade_xml_get_widget( xml,
								  "radiobutton_baud_rate_300" );
    self->radio_buttons[RADIO_BUTTON_1200] = glade_xml_get_widget( xml,
								   "radiobutton_baud_rate_1200" );
    self->radio_buttons[RADIO_BUTTON_2400] = glade_xml_get_widget( xml,
								   "radiobutton_baud_rate_2400" );
    self->radio_buttons[RADIO_BUTTON_9600] = glade_xml_get_widget( xml,
								   "radiobutton_baud_rate_9600" );
    self->radio_buttons[RADIO_BUTTON_19200] = glade_xml_get_widget( xml,
								    "radiobutton_baud_rate_19200" );
    self->radio_buttons[RADIO_BUTTON_57600] = glade_xml_get_widget( xml,
								    "radiobutton_baud_rate_57600" );
    self->radio_buttons[RADIO_BUTTON_115200] = glade_xml_get_widget( xml,
								     "radiobutton_baud_rate_115200" );
    self->spinbutton_sleep_time              = glade_xml_get_widget( xml,
								     "spinbutton_sleep_time" );
    self->imagemenuitem_sobre        = glade_xml_get_widget( xml,
							     "imagemenuitem_sobre" );
    self->dialog_about               = glade_xml_get_widget( xml,
							     "dialog_about" );
    self->checkbutton_two_stop_bits  = glade_xml_get_widget( xml,
							     "checkbutton_two_stop_bits" );
    self->checkbutton_parity_bit  = glade_xml_get_widget( xml,
							  "checkbutton_parity_bit" );
    self->checkbutton_parity_odd  = glade_xml_get_widget( xml,
							  "checkbutton_parity_odd" );
    self->spinbutton_sleep_time  = glade_xml_get_widget( xml,
							  "spinbutton_sleep_time" );
    self->spinbutton_many_times  = glade_xml_get_widget( xml,
							  "spinbutton_many_times" );
    self->entry_byte  = glade_xml_get_widget( xml,
					      "entry_byte" );
    /* widget:main_window */
    g_signal_connect( G_OBJECT(self->main_window),
		      "delete_event",
		      G_CALLBACK( gearserial_interface_event_handler ),
		      self );
    g_signal_connect( G_OBJECT(self->main_window),
		      "destroy",
		      G_CALLBACK( gearserial_interface_destroy ),
		      self );

    /* widget:imagemenuitem_abrir_serial */
    g_signal_connect( G_OBJECT( self->imagemenuitem_abrir_serial ),
		      "activate",
		      G_CALLBACK( gearserial_interface_callback_handler ),
		      self );
    g_object_set_data( G_OBJECT( self->imagemenuitem_abrir_serial ),
		       "handler",
		       GUINT_TO_POINTER( GEARSERIAL_INTERFACE_IMAGEMENUITEM_ABRIR_SERIAL ) );

    /* widget:dialog_abre_serial */
    g_signal_connect( GTK_WIDGET( self->dialog_abre_serial ),
		      "response",
		      G_CALLBACK( gearserial_interface_dialog_handler ),
		      self );
    g_object_set_data( G_OBJECT( self->dialog_abre_serial ),
		       "handler",
		       GUINT_TO_POINTER( GEARSERIAL_INTERFACE_DIALOG_ABRE_SERIAL ) );
    
    /* widget:radio_button_group */
    g_signal_connect( GTK_WIDGET( self->radio_buttons[RADIO_BUTTON_300] ),
		      "toggled",
		      G_CALLBACK( gearserial_interface_callback_handler ),
		      self );
    g_object_set_data( G_OBJECT( self->radio_buttons[RADIO_BUTTON_300] ),
		       "handler",
		       GUINT_TO_POINTER( GEARSERIAL_INTERFACE_RADIO_BUTTON ) );    
    g_object_set_data( G_OBJECT( self->radio_buttons[RADIO_BUTTON_300] ),
		       "radio_button",
		       GUINT_TO_POINTER( RADIO_BUTTON_300 ) );
    
    g_signal_connect( GTK_WIDGET( self->radio_buttons[RADIO_BUTTON_1200] ),
		      "toggled",
		      G_CALLBACK( gearserial_interface_callback_handler ),
		      self );
    g_object_set_data( G_OBJECT( self->radio_buttons[RADIO_BUTTON_1200] ),
		       "handler",
		       GUINT_TO_POINTER( GEARSERIAL_INTERFACE_RADIO_BUTTON ) );    
    g_object_set_data( G_OBJECT( self->radio_buttons[RADIO_BUTTON_1200] ),
		       "radio_button",
		       GUINT_TO_POINTER( RADIO_BUTTON_1200 ) );
    
    g_signal_connect( GTK_WIDGET( self->radio_buttons[RADIO_BUTTON_2400] ),
		      "toggled",
		      G_CALLBACK( gearserial_interface_callback_handler ),
		      self );
    g_object_set_data( G_OBJECT( self->radio_buttons[RADIO_BUTTON_2400] ),
		       "handler",
		       GUINT_TO_POINTER( GEARSERIAL_INTERFACE_RADIO_BUTTON ) );
    g_object_set_data( G_OBJECT( self->radio_buttons[RADIO_BUTTON_2400] ),
		       "radio_button",
		       GUINT_TO_POINTER( RADIO_BUTTON_2400 ) );
    
    g_signal_connect( GTK_WIDGET( self->radio_buttons[RADIO_BUTTON_9600] ),
		      "toggled",
		      G_CALLBACK( gearserial_interface_callback_handler ),
		      self );
    g_object_set_data( G_OBJECT( self->radio_buttons[RADIO_BUTTON_9600] ),
		       "handler",
		       GUINT_TO_POINTER( GEARSERIAL_INTERFACE_RADIO_BUTTON ) );
    g_object_set_data( G_OBJECT( self->radio_buttons[RADIO_BUTTON_9600] ),
		       "radio_button",
		       GUINT_TO_POINTER( RADIO_BUTTON_9600 ) );

    g_signal_connect( GTK_WIDGET( self->radio_buttons[RADIO_BUTTON_19200] ),
		      "toggled",
		      G_CALLBACK( gearserial_interface_callback_handler ),
		      self );
    g_object_set_data( G_OBJECT( self->radio_buttons[RADIO_BUTTON_19200] ),
		       "handler",
		       GUINT_TO_POINTER( GEARSERIAL_INTERFACE_RADIO_BUTTON ) );    
    g_object_set_data( G_OBJECT( self->radio_buttons[RADIO_BUTTON_19200] ),
		       "radio_button",
		       GUINT_TO_POINTER( RADIO_BUTTON_19200 ) );

    g_signal_connect( GTK_WIDGET( self->radio_buttons[RADIO_BUTTON_57600] ),
		      "toggled",
		      G_CALLBACK( gearserial_interface_callback_handler ),
		      self );
    g_object_set_data( G_OBJECT( self->radio_buttons[RADIO_BUTTON_57600] ),
		       "handler",
		       GUINT_TO_POINTER( GEARSERIAL_INTERFACE_RADIO_BUTTON ) );    
    g_object_set_data( G_OBJECT( self->radio_buttons[RADIO_BUTTON_57600] ),
		       "radio_button",
		       GUINT_TO_POINTER( RADIO_BUTTON_57600 ) );

    g_signal_connect( GTK_WIDGET( self->radio_buttons[RADIO_BUTTON_115200] ),
		      "toggled",
		      G_CALLBACK( gearserial_interface_callback_handler ),
		      self );
    g_object_set_data( G_OBJECT( self->radio_buttons[RADIO_BUTTON_115200] ),
		       "handler",
		       GUINT_TO_POINTER( GEARSERIAL_INTERFACE_RADIO_BUTTON ) );    
    g_object_set_data( G_OBJECT( self->radio_buttons[RADIO_BUTTON_115200] ),
		       "radio_button",
		       GUINT_TO_POINTER( RADIO_BUTTON_115200 ) );

    /* widget:button_start */    
    g_signal_connect( GTK_WIDGET( self->button_start ),
		      "clicked",
		      G_CALLBACK( gearserial_interface_callback_handler ),
		      self );
    g_object_set_data( G_OBJECT( self->button_start ),
		       "handler",
		       GUINT_TO_POINTER( GEARSERIAL_INTERFACE_BUTTON_START ) );    

    /* widget:button_stop */
    g_signal_connect( GTK_WIDGET( self->button_stop ),
		      "clicked",
		      G_CALLBACK( gearserial_interface_callback_handler ),
		      self );
    g_object_set_data( G_OBJECT( self->button_stop ),
		       "handler",
		       GUINT_TO_POINTER( GEARSERIAL_INTERFACE_BUTTON_STOP ) );

    /* widget:imagemenuitem_sobre */
    g_signal_connect( G_OBJECT( self->imagemenuitem_sobre ),
		      "activate",
		      G_CALLBACK( gearserial_interface_callback_handler ),
		      self );
    g_object_set_data( G_OBJECT( self->imagemenuitem_sobre ),
		       "handler",
		       GUINT_TO_POINTER( GEARSERIAL_INTERFACE_IMAGEMENUITEM_SOBRE ) );

    /* widget:dialog_dialog_about */
    g_signal_connect( G_OBJECT( self->dialog_about ), "delete-event",
		      G_CALLBACK( gearserial_interface_event_handler ), NULL);
    g_signal_connect( GTK_WIDGET( self->dialog_about ),
		      "response",
		      G_CALLBACK( gearserial_interface_dialog_handler ),
		      self );
    g_object_set_data( G_OBJECT( self->dialog_about ),
		       "handler",
		       GUINT_TO_POINTER( GEARSERIAL_INTERFACE_DIALOG_ABOUT ) );
    
    gtk_widget_show_all( self->main_window );
    gtk_widget_set_sensitive( self->action_area,
			      FALSE );

    g_object_unref( xml );
    return EXIT_SUCCESS;
}


/* Callbacks and Events *******************************************************/

static void
gearserial_interface_dialog_handler( GtkWidget *widget,
				     gint arg1,
				     gpointer user_data )
{
    GearSerialInterface *self = (GearSerialInterface*) user_data;
    gint handler = (gint) g_object_get_data( G_OBJECT( widget ), "handler" );

    switch( handler )
    {
    case GEARSERIAL_INTERFACE_DIALOG_ABOUT:
    {
	switch(arg1)
	{
	case GTK_RESPONSE_CANCEL:
	{
	    gtk_widget_hide_all( self->dialog_about );
	    break;
	}
	default:
	{
	    break;
	}
	}
    }
    case GEARSERIAL_INTERFACE_DIALOG_ABRE_SERIAL:
    {
	switch(arg1)
	{
	case GTK_RESPONSE_OK:
	{
	    const gchar *path = NULL;

	    path = gtk_entry_get_text( GTK_ENTRY(self->entry_abre_serial ) );
	    if( gearserial_open_serial( self->gserial,
					(char*) path ) == EXIT_SUCCESS )
	    {
		gearserial_set_raw_mode( self->gserial );
		gtk_widget_set_sensitive( self->action_area,
					  TRUE );
	    }
	    
	    gtk_widget_hide_all( self->dialog_abre_serial );				    
	    break;
	}
	case GTK_RESPONSE_CANCEL:
	{
	    gtk_widget_hide_all( self->dialog_abre_serial );
	    break;
	}
	}
	break;
    }
    default:
    {
	break;
    }
    }
}

static void
gearserial_interface_callback_handler( GtkWidget *widget,
				       gpointer user_data )
{
    GearSerialInterface *self = (GearSerialInterface*) user_data;
    gint handler = (gint) g_object_get_data( G_OBJECT( widget ), "handler" );

    switch( handler )
    {
    case GEARSERIAL_INTERFACE_IMAGEMENUITEM_SOBRE:
    {
	gtk_widget_show_all(self->dialog_about);
	break;
    }
    case GEARSERIAL_INTERFACE_BUTTON_START:
    {
	/* TODO */
	GearSerialConf *conf = NULL;

	conf = gearserial_conf_new();
	

	conf->boo_two_stop_bits = gtk_toggle_button_get_active(
	    GTK_TOGGLE_BUTTON(self->checkbutton_two_stop_bits));
	conf->boo_parity_bit = gtk_toggle_button_get_active(
	    GTK_TOGGLE_BUTTON(self->checkbutton_parity_bit));
	conf->boo_parity_odd = gtk_toggle_button_get_active(
	    GTK_TOGGLE_BUTTON(self->checkbutton_parity_odd));
	
	conf->sleep_time = gtk_spin_button_get_value_as_int(
	    GTK_SPIN_BUTTON( self->spinbutton_sleep_time ) );
	conf->many_times = gtk_spin_button_get_value_as_int(
	    GTK_SPIN_BUTTON( self->spinbutton_many_times ) );

	gearserial_configure( self->gserial,
			      conf );
	XFREE( conf );
	
	gearserial_send( self->gserial,
			 (const char*) gtk_entry_get_text(
			     GTK_ENTRY(self->entry_byte) )); 
	
	
	break;
    }
    case GEARSERIAL_INTERFACE_BUTTON_STOP:
    {
	/* TODO */
	break;
    }
    case GEARSERIAL_INTERFACE_IMAGEMENUITEM_ABRIR_SERIAL:
    {
	gtk_widget_show_all( self->dialog_abre_serial );
	break;
    }
    case GEARSERIAL_INTERFACE_RADIO_BUTTON:
    {
	gint radio_button = (gint) g_object_get_data( G_OBJECT( widget ),
						      "radio_button" );
	if( gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON( widget)) )
	{
	    switch( radio_button )
	    {
	    case RADIO_BUTTON_300:
	    {
		gearserial_set_baudrate( self->gserial,
					 B300 );
		break;
	    }
	    case RADIO_BUTTON_1200:
	    {
		gearserial_set_baudrate( self->gserial,
					 B1200 );
		break;
	    }
	    case RADIO_BUTTON_2400:
	    {
		gearserial_set_baudrate( self->gserial,
					 B2400 );
		break;
	    }
	    case RADIO_BUTTON_9600:
	    {
		gearserial_set_baudrate( self->gserial,
					 B9600 );
		break;
	    }
	    case RADIO_BUTTON_19200:
	    {
		gearserial_set_baudrate( self->gserial,
					 B19200 );
		break;
	    }
	    case RADIO_BUTTON_57600:
	    {
		gearserial_set_baudrate( self->gserial,
					 B57600 );
		break;
	    }
	    case RADIO_BUTTON_115200:
	    {
		gearserial_set_baudrate( self->gserial,
					 B115200 );
		break;
	    }
	    }
	}
	break;
    }    
    default:
    {
	break;
    }
    }

}

static gint
gearserial_interface_event_handler(GtkWidget *widget,
				   GdkEvent *event,
				   gpointer user_data )
{
    gint handler = (gint) g_object_get_data( G_OBJECT(widget), "handler");

    switch( handler )
    {
    case GEARSERIAL_INTERFACE_MAIN_WINDOW:
    {	
	return FALSE;
	break;
    }
    default:
    {
	gtk_widget_hide_all( GTK_WIDGET( widget ) );	
	break;
    }
    }
    
    return TRUE;
}

static void
gearserial_interface_destroy( GtkWidget *widget,
			      gpointer user_data )
{
    gtk_main_quit();
}
